Synchronizing Markdown Notes to NotebookLM Using Google Apps Script
TLDR
- NotebookLM currently does not support direct synchronization of Markdown (
.md) files, and repeated uploads result in duplicate sources, preventing automatic updates. - By creating an automation workflow via Google Apps Script (GAS), you can convert local Markdown files into Google Docs and leverage Google Drive's synchronization mechanism to achieve automatic updates for NotebookLM.
- Core logic: GAS monitors the source folder, writes Markdown content into Google Docs, and overwrites the content when updates occur, ensuring that NotebookLM's citations and conversation history remain uninterrupted.
- It is recommended to use a "Chunking" strategy to handle long notes to avoid exceeding Google Docs' single-write limits.
- It is recommended to encapsulate the core synchronization logic into a Library to facilitate sharing across multiple projects and maintainability.
NotebookLM's Synchronization Mechanism and Pain Points
NotebookLM currently supports synchronization from Google Drive for formats such as Google Docs, Google Slides, PDF, and Word (.docx). When a cloud file is updated, NotebookLM displays a synchronization prompt.
When you might encounter this issue: When you are accustomed to writing notes in Markdown and wish to use these notes as a knowledge source for NotebookLM, while wanting them to update automatically as your notes iterate.
Current main pain points:
- Format incompatibility: The NotebookLM synchronization feature in Google Drive does not support reading
.mdfiles directly. - Duplicate upload mechanism: Even if the filename is the same, NotebookLM treats it as a brand-new source, leading to both old and new sources coexisting without the ability to update content directly.
- Complex directory structure: If notes contain subfolders, they cannot be selected and batch-synchronized at once.
Google Apps Script Implementation
To solve the aforementioned issues, we create a "relay service" via GAS to convert Markdown files into Google Docs.
1. Core Synchronization Logic
Paste the following code into your GAS project to handle recursive file scanning, Markdown reading, and the creation and updating of Google Docs.
/**
* Synchronize a single file to a Google Doc (with retry mechanism)
*/
function syncFileToGoogleDoc(sourceFile, targetFolder, targetDocName) {
const maxRetries = 3;
let attempt = 0;
let success = false;
while (attempt < maxRetries && !success) {
try {
attempt++;
const existingFiles = targetFolder.getFilesByName(targetDocName);
let targetDocFile = null;
while (existingFiles.hasNext()) {
const f = existingFiles.next();
if (f.getMimeType() === MimeType.GOOGLE_DOCS) {
targetDocFile = f;
break;
}
}
if (targetDocFile) {
if (sourceFile.getLastUpdated() > targetDocFile.getLastUpdated()) {
updateDocContent(targetDocFile.getId(), sourceFile);
}
} else {
createDocContent(targetFolder, targetDocName, sourceFile);
}
success = true;
} catch (e) {
if (attempt < maxRetries) {
Utilities.sleep(attempt * 3000);
} else {
throw new Error(`Failed after ${maxRetries} retries: ` + e.message);
}
}
}
}
/**
* Write long text content in chunks (Chunking Strategy)
*/
function writeContentInChunks(docBody, fullText) {
const CHUNK_SIZE = 20000;
docBody.setText("");
if (!fullText || fullText.length === 0) return;
for (let i = 0; i < fullText.length; i += CHUNK_SIZE) {
const chunk = fullText.substring(i, i + CHUNK_SIZE);
const paragraphs = docBody.getParagraphs();
const lastParagraph = paragraphs[paragraphs.length - 1];
if (lastParagraph) {
lastParagraph.appendText(chunk);
} else {
docBody.appendParagraph(chunk);
}
Utilities.sleep(150);
}
}When you might encounter this issue: When the note content is too long and exceeds the single-write character limit of Google Docs, synchronization will fail, necessitating the use of a chunking strategy.
Deployment and Automation Recommendations
1. Modular Management
If you have multiple note projects, it is recommended to deploy the core synchronization logic as a "Library."
- Click "Deploy" -> "New deployment" -> Select "Library" in the core project.
- Copy the "Script ID" and reference it in the "Library" section of other projects.
- Call it via
SyncUtils.startSyncEngine(...)and configure different allowlists/blocklists in each project.
2. Setting Up Automation Triggers
- Click the "Triggers" icon on the left side of GAS.
- Add a trigger and select the main function (e.g.,
syncCloudyWingLog). - For the event source, select "Time-driven." It is recommended to set it to run once per hour to ensure notes remain synchronized with NotebookLM.
TIP
Upon the first execution, Google will request authorization to access Google Drive and create files. If a "Google hasn't verified this app" warning appears, click "Advanced" and select "Go to... (unsafe)" to complete the authorization.
Changelog
- 2026-01-27 Initial document creation.
